/**
 * Delta
 * Copyright 2005 by Jeff Heaton(jeff@jeffheaton.com)
 *
 * Example program from Chapter 4
 * Programming Neural Networks in Java
 * http://www.heatonresearch.com/articles/series/1/
 *
 * This software is copyrighted. You may use it in programs
 * of your own, without restriction, but you may not
 * publish the source code without the author's permission.
 * For more information on distributing this code, please
 * visit:
 *    http://www.heatonresearch.com/hr_legal.php
 *
 * @author Jeff Heaton
 * @version 1.1
 */
public class Delta {

  /**
   * Weight for neuron 1
   */
  double w1;

  /**
   * Weight for neuron 2
   */
  double w2;

  /**
   * Weight for neuron 3
   */
  double w3;

  /**
   * Learning rate
   */
  double rate = 0.5;

  /**
   * Current epoch #
   */
  int epoch = 1;

  /**
   * @param i1 Input to neuron 1
   * @param i2 Input to neuron 2
   * @param i3 Input to neuron 3
   * @return the output from the neural network
   */
  protected double recognize(double i1,double i2,double i3)
  {
    double a = (w1*i1)+(w2*i2)+(w3*i3);
    return(a*.5);
  }

  /**
   * This method will calculate the error between the
   * anticipated output and the actual output.
   *
   * @param actual The actual output from the neural network.
   * @param anticipated The anticipated neuron output.
   * @return The error.
   */
  protected double getError(double actual,double anticipated)
  {
    return(anticipated-actual);
  }

  /**
   * The learningFunction implements the delta rule.
   * This method will return the weight adjustment for
   * the specified input neuron.
   *
   * @param rate The learning rate
   * @param input The input neuron we're processing
   * @param error The error between the actual output
   * and anticipated output.
   * @return The amount to adjust the weight by.
   */
  protected double trainingFunction(
    double rate,double input,double error)
  {
    return rate*input*error;
  }

  /**
   * Present a pattern and learn from it.
   *
   * @param i1 Input to neuron 1
   * @param i2 Input to neuron 2
   * @param i3 Input to neuron 3
   * @param anticipated The anticipated output
   */
  protected void presentPattern(
    double i1,double i2,double i3,double anticipated)
  {
    double error;
    double actual;
    double delta;

    // run the net as is on training data
    // and get the error
    System.out.print("Presented [" + i1 + "," + i2
                     + "," + i3 + "]");
    actual = recognize(i1,i2,i3);
    error = getError(actual,anticipated);
    System.out.print(" anticipated=" + anticipated);
    System.out.print(" actual=" + actual);
    System.out.println(" error=" + error);

    // adjust weight 1
    delta = trainingFunction(rate,i1,error);
    w1+=delta;

    // adjust weight 2
    delta = trainingFunction(rate,i2,error);
    w2+=delta;

    // adjust weight 3
    delta = trainingFunction(rate,i3,error);
    w3+=delta;
  }
  /**
   * Process one epoch. Here we learn from all three training
   * samples and then update the weights based on error.
   */

  protected void epoch()
  {
    System.out.println("***Beginning Epoch #" + epoch+"***");
    presentPattern(0,0,1,0);
    presentPattern(0,1,1,0);
    presentPattern(1,0,1,0);
    presentPattern(1,1,1,1);
    epoch++;
  }

  /**
   * This method loops through 100 epochs.
   */
  public void run()
  {
    for ( int i=0;i<100;i++ ) {
      epoch();
    }
  }

  /**
   * Main method just instanciates a delta object and calls
   * run.
   *
   * @param args Not used
   */
  public static void main(String args[])
  {
    Delta delta = new Delta();
    delta.run();

  }
}